/**
 * 
 */
package com.gragra.function;
import it.unimi.dsi.fastutil.doubles.Double2ObjectAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import com.gragra.sampling.sequentialStructure.ExtensionLevels;
import com.gragra.sampling.sequentialStructure.WordAndTagHolder;
import com.gragra.sampling.sequentialStructure.WordType;
import com.gragra.sequentiaDataGenerator.BaseGenerator;
import com.gragra.sequentiaDataGenerator.EmptySegmentation;
import com.gragra.util.OpenUnitElementCounter;
import com.gragra.util.OpenUnitElementCounter.MappingIterator;
import com.gragra.util.StringToInt;
/**
 * @author Christoph Teichmann
 * 29.09.2013
 */
public class FindNounsOne
{
	/**
	 * 
	 */
	private final static String[] tags = {"NOUN"};
	/**
	 * 
	 */
	private final static String[] tagsExtended = {"NOUN","X","ADJ"};
	/**
	 * 
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException
	{
		String prefix = args[0];
		String prefixFunct = args[1];
		int number = Integer.parseInt(args[2]);
		for(String[] t : new String[][] {tags,tagsExtended})
		{
			String also;
			String[] a = new String[t.length+3];
			if(t == tags)
			{also = "narrow";}
			else
			{also = "wide";}
			for(int i=0;i<t.length;++i)
			{a[i+3] = t[i];}
			Integer amount = 1;
			{
				a[2] = amount.toString();
				double[] prec = new double[number];
				double[] rec = new double[number];
				double[] f = new double[number];
				for(int i=0;i<number;++i)
				{
					a[0] = prefix;
					a[1] = prefixFunct;
					double[] arr = m(a);
					prec[i] = arr[0];
					rec[i] = arr[1];
					f[i] = arr[2];
				}
				double precM = makeMean(prec);
				double precV = makeVariance(precM,prec);
				double recM = makeMean(rec);
				double recV = makeVariance(recM, rec);
				double fM = makeMean(f);
				double fV = makeVariance(fM,f);
				System.out.println("Precision Mean "+also);
				System.out.println(precM);
				System.out.println("Precision Variance "+also);
				System.out.println(precV);
				System.out.println("Recall Mean "+also);
				System.out.println(recM);
				System.out.println("Recall Variance "+also);
				System.out.println(recV);
				System.out.println("F-Score Mean "+also);
				System.out.println(fM);
				System.out.println("F-Score Variance "+also);
				System.out.println(fV);
			}
		}
	}
	/**
	 * 
	 * @param precM
	 * @param prec
	 * @return
	 */
	private static double makeVariance(double precM, double[] prec)
	{
		double m = 0.0;
		for(double d : prec)
		{m += Math.pow(d - precM, 2.0);}
		return m/prec.length;
	}
	/**
	 * 
	 * @param prec
	 * @return
	 */
	private static double makeMean(double[] prec)
	{
		double m = 0.0;
		for(double d : prec)
		{
			m += d;
		}
		return m/prec.length;
	}
	/**
	 * @param args
	 */
	public static double[] m(String[] args) throws IOException
	{
		BufferedReader br = new BufferedReader(new FileReader(args[0]));
		OpenUnitElementCounter oue = new OpenUnitElementCounter();
		String line;
		BaseGenerator bg = new BaseGenerator(new EmptySegmentation());
		while((line = br.readLine()) != null)
		{
			WordAndTagHolder wth = bg.transferSingle(line);
			for(int i=0;i<wth.getLength();++i)
			{oue.add(wth.getExtensionInformation().getInfiniteInformation(i, ExtensionLevels.ContextTagLevel),wth.getWord(i),1.0);}
		}
		br.close();
		Int2DoubleOpenHashMap scores = new Int2DoubleOpenHashMap();
		MappingIterator mi = oue.getIterator();
		while(mi.hasNext())
		{
			mi.setToNext();
			scores.addTo(mi.getCurrentUnit(),mi.getCurrentValue()/(mi.getCurrentUnitSum())*Math.log(mi.getCurrentValue()/mi.getCurrentUnitSum()));
		}
		Double2ObjectAVLTreeMap<IntArrayList> heap = new Double2ObjectAVLTreeMap<IntArrayList>();
		for(Map.Entry<Integer, Double> ent : scores.entrySet())
		{
			IntArrayList l = heap.get(ent.getValue());
			if(l == null)
			{
				l = new IntArrayList();
				heap.put(ent.getValue(), l);
			}
			l.add(ent.getKey());
		}
		int size = Integer.parseInt(args[2]);
		IntSet is = new IntOpenHashSet();
		for(IntArrayList il : heap.values())
		{
			boolean b = false;
			for(int i=0;i<il.size();++i)
			{
				if(is.size() >= size)
				{
					b = true;
					break;
				}
				is.add(il.getInt(i));
			}
			if(b)
			{break;}
		}
		br = new BufferedReader(new FileReader(args[0]));
		bg = new BaseGenerator(new EmptySegmentation());
		BufferedWriter bw = new BufferedWriter(new FileWriter(args[1]));
		boolean first = true;
		IntSet gold = new IntOpenHashSet();
		for(int i=3;i<args.length;++i)
		{gold.add(StringToInt.ensure(args[i]));}
		double hits = 0.0;
		double proposals = 0.0;
		double all = 0.0;
		while((line = br.readLine()) != null)
		{
			if(first)
			{first = false;}
			else
			{bw.newLine();}
			WordAndTagHolder wth = bg.transferSingle(line);
			for(int i=0;i<wth.getLength();++i)
			{
				if(is.contains(wth.getExtensionInformation().getInfiniteInformation(i, ExtensionLevels.ContextTagLevel)))
				{
					wth.getExtensionInformation().addInformation(i, ExtensionLevels.WordTypeLevel, WordType.Noun);
					++proposals;
					if(gold.contains(wth.getTag(i)))
					{++hits;}
				}
				if(gold.contains(wth.getTag(i)))
				{++all;}
			}
			bw.write(BaseGenerator.transferToString(wth));
		}
		br.close();
		bw.close();
		double prec = hits/proposals;
		double rec = hits/all;
		return new double[] {prec,rec,2*prec*rec/(prec+rec)};
	}
}